package com.one.blocks.rbac.manager;

import com.alicp.jetcache.anno.CacheInvalidate;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.one.blocks.mvc.manager.AbstractBatchManager;
import com.one.blocks.mvc.util.TreeUtil;
import com.one.blocks.rbac.constant.RbacConstant.MenuCache;
import com.one.blocks.rbac.controller.convert.SysMenuConvert;
import com.one.blocks.rbac.controller.vo.tree.SysMenuTreeNodeVo;
import com.one.blocks.rbac.domain.SysMenu;
import com.one.blocks.rbac.domain.SysRole;
import com.one.blocks.rbac.domain.SysRoleMenu;
import com.one.blocks.rbac.enums.MenuTypeEnum;
import com.one.blocks.rbac.enums.MenuVisibleEnum;
import com.one.blocks.rbac.enums.RoleTypeEnum;
import com.one.blocks.rbac.mapper.SysMenuMapper;
import com.one.blocks.rbac.util.PermissionHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import static com.one.blocks.rbac.constant.RbacConstant.ADMIN_PERMISSION;

/**
 * @author <a href="mailto:idler41@163.con">idler41</a> created on 2022-05-01 10:06:14
 */
@Slf4j
@Service
public class SysMenuManager extends AbstractBatchManager<SysMenuMapper, SysMenu> {

    @Autowired
    private SysMenuConvert sysMenuConvert;

    @Autowired
    private SysRoleMenuManager sysRoleMenuManager;

    @Autowired
    private SysMenuManager sysMenuManager;

    @Autowired
    public SysMenuManager(SysMenuMapper mapper) {
        super(mapper);
    }

    public Set<String> listPermission(SysRole sysRole) {
        if (RoleTypeEnum.PLATFORM_ADMIN.match(sysRole.getType())) {
            // 系统管理员角色查询平台配置表
            return Collections.singleton(ADMIN_PERMISSION);
        }

        // 普通角色查询被分配的权限
        return sysMenuManager.selectPerms(sysRole.getId());
    }

    public List<SysMenuTreeNodeVo> treeMenu(SysRole sysRole) {
        return TreeUtil.buildTree(sysMenuConvert.toTreeNodeList(selectMenuTree(sysRole)));
    }

    public List<SysMenuTreeNodeVo> treeSidebar(SysRole sysRole) {
        List<SysMenu> menus = selectMenuTree(sysRole);
        List<SysMenuTreeNodeVo> menuTree = new LinkedList<>();
        for (SysMenu menu : menus) {
            if (MenuVisibleEnum.YES.match(menu.getVisible()) && !MenuTypeEnum.BUTTON.match(menu.getType())) {
                menuTree.add(sysMenuConvert.toTreeNode(menu));
            }
        }
        return TreeUtil.buildTree(menuTree);
    }

    public List<SysMenu> selectMenuTree(SysRole sysRole) {
        if (RoleTypeEnum.PLATFORM_ADMIN.match(sysRole.getType())) {
            // 平台管理员直接走库而不是缓存，主要是避免新增目录在缓存中查不到
            return mapper.selectTree(null, null);
        }

        // 普通角色查询被分配的目录
        return sysMenuManager.selectMenuTree(sysRole.getId());
    }

    @CacheInvalidate(area = MenuCache.AREA, name = MenuCache.PERMS_ROLE_ID, key = "#roleId")
    @CacheInvalidate(area = MenuCache.AREA, name = MenuCache.MENU_ROLE_ID, key = "#roleId")
    @Transactional(rollbackFor = Exception.class)
    public boolean grant(Integer roleId, List<SysRoleMenu> sysRoleMenus) {
        sysRoleMenuManager.deleteByRoleId(roleId);
        sysRoleMenuManager.insertBatch(sysRoleMenus);
        return true;
    }

    @Cached(area = MenuCache.AREA, name = MenuCache.PERMS_ROLE_ID, key = "#roleId", cacheType = CacheType.BOTH)
    public Set<String> selectPerms(Integer roleId) {
        return PermissionHelper.listPermsToPermsSet(mapper.selectPerms(roleId));
    }

    @Cached(area = MenuCache.AREA, name = MenuCache.MENU_ROLE_ID, key = "#roleId", cacheType = CacheType.BOTH)
    public List<SysMenu> selectMenuTree(Integer roleId) {
        return mapper.selectTreeJoinRole(roleId, null, null);
    }

//    @CacheInvalidate(area = MenuCache.AREA, name = MenuCache.PERMS_ROLE_ID, key = "#roleId")
//    @CacheInvalidate(area = MenuCache.AREA, name = MenuCache.MENU_ROLE_ID, key = "#roleId")
//    public void clearCacheByRoleId(Integer roleId) {
//
//    }
}
